function reconstruct3D(configFN)
%% CLEAR UP WORKING SPACE
clc;

%% READ THE INPUT CONFIGURATION
t = cputime;
fid = fopen(configFN);
if fid < 0
    error('No input configuration in the directory');
end
nImgs = uint8(str2double(fgetl(fid)));
chromeMaskFN = fgetl(fid);
chromeImgFNs = cell(nImgs,1);
for i = 1:nImgs
    chromeImgFNs{i,1} = fgetl(fid);
end
objectMaskFN = fgetl(fid);
objectImgFNs = cell(nImgs,1);
for i = 1:nImgs
    objectImgFNs{i,1} = fgetl(fid);
end
fclose(fid);
disp(['Read input configuration in ',num2str(cputime-t),' seconds']);

%% READ IMAGES IN
t = cputime;
chromeMask = imread(chromeMaskFN,'jpg');
objectMask = imread(objectMaskFN,'jpg');
[nRs_c, nCs_c, nCls_c] = size(chromeMask);
[nRs_o, nCs_o, nCls_o] = size(objectMask);
chromeImgs = uint8(zeros(nRs_c, nCs_c, nCls_c, nImgs));
objectImgs = uint8(zeros(nRs_o, nCs_o, nCls_o, nImgs));
for i = 1:nImgs
    chromeImgs(:,:,:,i) = imread(chromeImgFNs{i,1});
    objectImgs(:,:,:,i) = imread(objectImgFNs{i,1});
end
disp(['Read images in ',num2str(cputime-t),' seconds']);

%% CALCULATE LIGHTING DIRECTIONS
t = cputime;
lights = zeros(3,nImgs);
chromeMaskGray = rgb2gray(chromeMask);
for i = 1:nImgs
    chromeImgGray = rgb2gray(chromeImgs(:,:,:,i));
    [lights(:,i), ~] = getLightDirs(chromeImgGray, chromeMaskGray);
    %disp(['Image',num2str(i),' light dir: [', num2str(lights(:,i)'),']']);
end
disp(['Calculated light directions in ', num2str(cputime-t), ' seconds']);

%% CALCULATE THE NORMAL FOR EACH SCENE POINT
t = cputime;
objectImgsGray = uint8(zeros(nRs_o, nCs_o, nImgs));
for i = 1:nImgs
    objectImgsGray(:,:,i) = rgb2gray(objectImgs(:,:,:,i));
end
normals = getNormals(lights, objectImgsGray, rgb2gray(objectMask));
disp(['Calculated normals in ', num2str(cputime-t), ' seconds']);

%% CALCULATING ALBEDO FOR EACH COLOR
t = cputime;
albedos = zeros(nRs_o, nCs_o, nCls_o);
for i = 1:nCls_o
    objectImgsSC = reshape(objectImgs(:,:,i,:),nRs_o, nCs_o, nImgs);
    objectMaskSC = objectMask(:,:,i);
    albedos(:,:,i) = getAlbedos(lights, normals, ...
                                objectImgsSC, objectMaskSC);
end
disp(['Calculated albedos in ', num2str(cputime-t), ' seconds']);

%% CALCULATE THE SURFACE
t = cputime;
surface = getSurface(normals, rgb2gray(objectMask));
disp(['Calculated surface in ',num2str(cputime-t),' seconds']);

%% PLOT THE REQUIRED ARTIFACTS
filePrefix = configFN(1:end-4);
fcount = 0;

%% figure 1-0: quiver normals
fcount = fcount+1;
figure(fcount);
quiver(1:2:nCs_o,1:2:nRs_o, ...
    normals(1:2:end,1:2:end,1),normals(1:2:end,1:2:end,2));
axis([1, nCs_o, 1, nRs_o]);
set(gca,'YDir','reverse');
xlabel('column pixels');
ylabel('row pixels');
title('Surface normal');
print('-djpeg',[filePrefix '_surface_normals']);

%% figure 1-1: RGB-encoded normals
fcount = fcount+1;
figure(fcount);
tmpImg = normals(:);
maxNorm = max(tmpImg);
minNorm = min(tmpImg);
dispNorm(:,:,:) = uint8((normals(:,:,:)-minNorm)/(maxNorm-minNorm)*255);
imshow(dispNorm);
xlabel([num2str(1),' <---column pixels---> ',num2str(nCs_o)]);
ylabel([num2str(nRs_o),' <---row pixels---> ',num2str(1)]);
title('RGB-encoded normals');
imwrite(dispNorm,[filePrefix,'_RGB_normals.jpg'],'jpg');

%% figure 2: albedo map
fcount = fcount+1;
figure(fcount);
imshow(uint8(albedos));
xlabel([num2str(1),' <---column pixels---> ',num2str(nCs_o)]);
ylabel([num2str(nRs_o),' <---row pixels---> ',num2str(1)]);
title('Albedo map of three colors');
imwrite(uint8(albedos),[filePrefix,'_albedo_map.jpg'],'jpg');

%% figure 3-1: 3D view 1
fcount = fcount+1;
figure(fcount);
surfl(1:nCs_o, 1:nRs_o, surface);
axis([1, nCs_o, 1, nRs_o, min(min(surface)), max(max(surface))]);
set(gca,'XDir', 'reverse');
view([1,1,10]);
shading interp;
colormap(gray);
xlabel('column pixels');
ylabel('row pixels');
title('3D viewpoint 1');
print('-djpeg',[filePrefix '_viewpoint1']);

%% figure 3-2: 3D view 2
fcount = fcount+1;
figure(fcount);
surfl(1:nCs_o, 1:nRs_o, surface);
axis([1, nCs_o, 1, nRs_o, min(min(surface)), max(max(surface))]);
set(gca,'XDir', 'reverse');
view([1,-1,10]);
shading interp;
colormap(gray);
xlabel('column pixels');
ylabel('row pixels');
title('3D viewpoint 2');
print('-djpeg',[filePrefix '_viewpoint2']);

%% figure 3-3: 3D view 3
fcount = fcount+1;
figure(fcount);
surfl(1:nCs_o, 1:nRs_o, surface);
axis([1, nCs_o, 1, nRs_o, min(min(surface)), max(max(surface))]);
set(gca,'XDir', 'reverse');
view([-1,1,10]);
shading interp;
colormap(gray);
xlabel('column pixels');
ylabel('row pixels');
title('3D viewpoint 3');
print('-djpeg',[filePrefix '_viewpoint3']);

end

